package OrdersSystem;

import DBSystem.*;
import Deliveries.DeliveriesComm;
import java.sql.Time;
import java.util.Date;

/**
 * A class that represents the orders submitted into the system.
 * 
 * @author iSolutions Orders Team
 *
 */
public class Order {
	/**
	 * Contains the number, which identifies uniquely the order.  
	 */
	private int orderID;
	/**
	 * Contains the number, which identifies uniquely the product.  
	 */
	private int productID;
	/**
	 * Contains the number, which identifies uniquely the customer. 
	 */	
	private int customerID;
	/**
	 * Contains the number, which specifies the quantity of the ordered product.  
	 */
	private float productQuantity; // number of palettes
	/**
	 * Contains the demanded delivery Date.  
	 */
	private Date deliveryDate;
	/**
	 * Contains the demanded delivery Time. 
	 */
	private Time deliveryTime;
	/**
	 * Contains the comments made by the user. 
	 */
	private String comments;
	/**
	 * Contains the Date on which the order is delivered. 
	 */
	private Date orderDate; 
	/**
	 * Contains the alternative address, where the order may be delivered.  
	 */
	private String deliveryAddressAlt;
	/**
	 * Contains the external company id, which the user may have.  
	 */
	private int extCompanyID;
	/**
	 * Contains the communicator with database.  
	 */
	private  static DBSystemComm dbCommunicator = new DBSystemComm();
	/**
	 * Contains the communicator with Deliveries system.  
	 */
	private static DeliveriesComm deliveries = new DeliveriesComm();

	
	// constructors
	
	/**
	 * A Default Constructor for this class.
	 * 
     */
	public Order() {}
	
	/**
	 * A Constructor, which receives values for all of the order's attributes.
	 * 
	 * @param customerID the number, which uniquely identifies a customer.
	 * @param deliveryAddressAlt the alternative address, where the order may be delivered.
	 * @param extCompanyID the external company id, which the user may have.
	 * @param deliveryDate the demanded delivery Date.
	 * @param deliveryTime the demanded delivery time.
	 * @param productID the number, which identifies uniquely the product.
	 * @param productQuantity the number of products.
	 * @param comments alternatively specifies what the user may additionally desire about the order.
	 * 
     */
	public Order(int customerID, String deliveryAddressAlt, int extCompanyID, Date deliveryDate, Time deliveryTime,
			 int productID, float productQuantity, String comments) // there are all of the fields
	{
		this.customerID = customerID;
		this.deliveryAddressAlt = deliveryAddressAlt;
		this.extCompanyID = extCompanyID;
		this.deliveryDate = deliveryDate;
		this.deliveryTime = deliveryTime;
		this.productID = productID;
		this.productQuantity = productQuantity;
		this.comments = comments;
		orderDate = new Date();
			
	}
		
	/* #######################accessors############################### */
	/**
	 * Gets an attribute.
	 * @return orderID.
	*/
	public int getOrderID()
	{
		return orderID;
	}
	
	/**
	 * Gets an attribute.
	 * @return productID.
	*/
	public int getProductID()
	{
		return productID;
	}
	
	/**
	 * Gets an attribute.
	 * @return customerID.
	*/
	public int getCustomerID()
	{
		return customerID;
	}
	
	/**
	 * Gets an attribute.
	 * @return orderHistory.
	*/
	public float getProductQuantity()
	{
		return productQuantity;
	}
	
	/**
	 * Gets an attribute.
	 * @return comments.
	*/
	public String getComments()
	{
		return comments;
	}
	
	/**
	 * Gets an attribute.
	 * @return orderDate.
	*/
	public Date getOrderDate()
	{
		return orderDate;
	}
	
	/**
	 * Gets an attribute.
	 * @return deliveryDate.
	*/
	public Date getDeliveryDate()
	{
		return deliveryDate;
	}
	
	/**
	 * Gets an attribute.
	 * @return deliveryTime.
	*/
	public Time getDeliveryTime()
	{
		return deliveryTime;
	}
	
	/**
	 * Gets an attribute.
	 * @return deliveryAddressAlt.
	*/
	public String getDeliveryAddressAlt()
	{
		return deliveryAddressAlt;
	}
	
	/**
	 * Gets an attribute.
	 * @return extCompanyID.
	*/
	public int getExtCompanyID() {
		return extCompanyID;
	}
	
	/*#################### mutators #############################*/
	
	/**
	 * Modifies an attribute.
	 * @param quantity.
	*/
	public void setProductQuantity(float quantity)
	{
		productQuantity = quantity;
	}
	
	/**
	 * Modifies an attribute.
	 * @param productID.
	*/
	public void setProductID(int productID)
	{
		this.productID = productID;
	}
	
	/**
	 * Modifies an attribute.
	 * @param comments.
	*/
	public void setComments(String comments)
	{
		this.comments = comments;
	}
	
	/**
	 * Modifies an attribute.
	 * @param date.
	*/
	public void setDeliveryDate(Date date)
	{
		deliveryDate = date;
	}
	
	/**
	 * Modifies an attribute.
	 * @param orderID.
	*/
	public void setOrderID(int orderID) {
		this.orderID = orderID;
	}
	/*##############################private methods #################################3*/
	
	/**
	 * Generates the orderID of a new order.
	 *
	*/
	private int generateOrderID()
	{	
		int lastID = dbCommunicator.getLastOrderID();
		if (lastID == 0) { // if this is the first order made in the system
			return 1;
		}
		return (lastID + 1); // this will be the ID of the current order
	}
	
	/**
	 * Stores a new order into the database.
	 * 
	*/
	private void storeOrder()
	{
		dbCommunicator.storeData(this);
	}
	
	/**
	 * Validates the parameters of the newly inserted order.
	 * The requested delivery time should be from a minimum of 24 hours to a maximum of 7 days. 
     * and the quantity should be an integer number.
     * Return true if the order is validated successfully and false, otherwise.
	 * 
	*/
	private boolean validateOrder()  // check if some of the orders parameters are valid
	{
		boolean checkTime = true;
		boolean checkQuantity = true;
		long deliveryTimeInMs = deliveryDate.getTime();
		long orderTimeInMs = orderDate.getTime();
		
		long diff = deliveryTimeInMs - orderTimeInMs;
		long diffInDays = diff/(24*60*60*1000);
		long diffInHours = diff/(60*60*1000);
		if (diffInDays >= 7 || diffInHours < 24) {
			checkTime = false;
			
		}
		if( productQuantity != Math.round(productQuantity)) // if the number is not integer
		    checkQuantity = false;
		return (checkTime && checkQuantity); // both of the conditions should hold
	}
	
	/**
	 * Stores the order into the database and asks the Deliveries system to confirm its fulfillment.
	 * Returns an appropriate message if the order was served successfully or it can't be presently served.
	 * 
	*/
	private String confirmOrder()
	{
		orderID = generateOrderID(); // generate a new order ID an confirm the order
		storeOrder(); // store the order in the database
		Date estimatedDeliveryDate = deliveries.requestOrderConfirmation(orderID);
		if (estimatedDeliveryDate == null) {
			// delete the newly stored order from the database, since it can't be served
			dbCommunicator.deleteOrder(orderID);
			return "We apologise, but your order can't be served. Please, try again a few days latter.";
		} else {
			return "The order is confirmed. Order ID is : " + orderID +" and estimated delivery date is: " + estimatedDeliveryDate.toString();
		}
	}
	
	/*#########################public methods######################################*/
	
	/**
	 * Submits a new order into the system, by validating, storying and asking from the Deliveries System to confirm it.
	 * It returns the message deriving either from the order's confirmation or the order's validation.
	*/
	public String submitOrder()
	{
		if (validateOrder()) // try to validate the order
		{
			return confirmOrder(); // if validation is successful, send it to deliveries department for confirmation
		} else {
		    return "Sorry the order has incorrect parameters!\nPlase make sure that the requested delivery time" +
		    		" is between 24h and 7 days. Also make sure that you order full palettes of products.";
		}  
	}
	
	/*#######################Test methods############################*/
	
	/**
	 * Test method for validateOrder.
	 * 
	 * @return Returns true if the order is valid, and false if it is not.
	 */
	public boolean testValidateOrder() {
		return validateOrder();
	}
	
	
	/**
	 * Test method for confirmOrder.
	 * 
	 * @return Returns true if the order is confirmed, and false if it is not.
	 */
	public boolean testConfirmOrder() {
		String result = confirmOrder();
		if(result.contains("We apologise, but your order can't be served. Please, try again a few days latter.")) {
			return false;
		}else {
			return true;
		}
	}
		
}
